#pragma once

#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <vector>
#include <optional>
#include <chrono>
#include <condition_variable>

template <typename T>
class ResourcePool {
public:
    using CreateFunc = std::function<std::shared_ptr<T>()>;
    using ValidateFunc = std::function<bool(const std::shared_ptr<T>&)>;
    
    struct Config {
        size_t initialSize = 0;         // 初始池大小
        size_t maxSize = 10;            // 最大池大小
        std::chrono::milliseconds maxIdleTime{60000}; // 资源最大空闲时间
        bool growOnDemand = true;       // 需要时是否自动增长
    };
    
    explicit ResourcePool(CreateFunc createFunc, 
                         ValidateFunc validateFunc = [](const std::shared_ptr<T>&) { return true; },
                         const Config& config = Config{});
    
    ~ResourcePool();
    
    // 获取资源
    std::shared_ptr<T> acquire(std::chrono::milliseconds timeout = std::chrono::milliseconds{0});
    
    // 释放资源回池
    void release(std::shared_ptr<T> resource);
    
    // 获取当前池大小
    size_t size() const;
    
    // 获取当前可用资源数量
    size_t availableCount() const;
    
    // 清空池
    void clear();
    
    // 调整池大小
    void resize(size_t newSize);

private:
    struct PoolItem {
        std::shared_ptr<T> resource;
        std::chrono::steady_clock::time_point lastUsed;
    };
    
    // 创建新资源
    std::shared_ptr<T> createResource();
    
    // 清理过期资源
    void cleanupExpiredResources();
    
    CreateFunc createFunc_;
    ValidateFunc validateFunc_;
    Config config_;
    
    mutable std::mutex mutex_;
    std::condition_variable cv_;
    std::queue<PoolItem> availableResources_;
    size_t inUseCount_ = 0;
    bool isShuttingDown_ = false;
};

// 模板类实现
template <typename T>
ResourcePool<T>::ResourcePool(CreateFunc createFunc, ValidateFunc validateFunc, const Config& config)
    : createFunc_(std::move(createFunc)), 
      validateFunc_(std::move(validateFunc)), 
      config_(config) {
    
    for (size_t i = 0; i < config_.initialSize; ++i) {
        auto resource = createResource();
        if (resource) {
            availableResources_.push({resource, std::chrono::steady_clock::now()});
        }
    }
}

template <typename T>
ResourcePool<T>::~ResourcePool() {
    std::unique_lock<std::mutex> lock(mutex_);
    isShuttingDown_ = true;
    lock.unlock();
    
    cv_.notify_all();
    clear();
}

template <typename T>
std::shared_ptr<T> ResourcePool<T>::acquire(std::chrono::milliseconds timeout) {
    std::unique_lock<std::mutex> lock(mutex_);
    
    // 尝试创建新资源的辅助函数
    auto tryCreateResource = [this]() -> std::shared_ptr<T> {
        if (config_.growOnDemand && (inUseCount_ + availableResources_.size() < config_.maxSize)) {
            auto resource = createResource();
            if (resource) {
                inUseCount_++;
                return resource;
            }
        }
        return nullptr;
    };
    
    auto waitUntil = std::chrono::steady_clock::now() + timeout;
    
    // 等待可用资源或超时
    auto waitPredicate = [this]() {
        return !availableResources_.empty() || isShuttingDown_;
    };
    
    if (timeout.count() > 0) {
        if (!cv_.wait_until(lock, waitUntil, waitPredicate)) {
            // 超时，尝试创建新资源
            return tryCreateResource();
        }
    } else if (availableResources_.empty()) {
        // 无可用资源，尝试创建新资源
        auto resource = tryCreateResource();
        if (resource) {
            return resource;
        }
        
        // 检查是否已达到最大容量，如果是则直接返回nullptr，避免无限等待
        if (inUseCount_ >= config_.maxSize) {
            return nullptr;
        }
        
        // 无超时，等待直到有可用资源
        cv_.wait(lock, waitPredicate);
    }
    
    if (isShuttingDown_) {
        return nullptr;
    }
    
    // 清理过期资源
    cleanupExpiredResources();
    
    // 如果没有可用资源，再次尝试创建
    if (availableResources_.empty()) {
        return tryCreateResource();
    }
    
    // 获取资源并验证
    auto item = availableResources_.front();
    availableResources_.pop();
    
    if (!validateFunc_(item.resource)) {
        // 资源无效，尝试创建新资源
        return tryCreateResource();
    }
    
    inUseCount_++;
    return item.resource;
}

template <typename T>
void ResourcePool<T>::release(std::shared_ptr<T> resource) {
    if (!resource) return;
    
    std::unique_lock<std::mutex> lock(mutex_);
    
    if (isShuttingDown_) {
        inUseCount_--;
        return;
    }
    
    // 验证资源是否有效
    if (validateFunc_(resource)) {
        availableResources_.push({resource, std::chrono::steady_clock::now()});
    }
    
    inUseCount_--;
    lock.unlock();
    
    cv_.notify_one();
}

template <typename T>
size_t ResourcePool<T>::size() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return availableResources_.size() + inUseCount_;
}

template <typename T>
size_t ResourcePool<T>::availableCount() const {
    std::lock_guard<std::mutex> lock(mutex_);
    return availableResources_.size();
}

template <typename T>
void ResourcePool<T>::clear() {
    std::lock_guard<std::mutex> lock(mutex_);
    while (!availableResources_.empty()) {
        availableResources_.pop();
    }
}

template <typename T>
void ResourcePool<T>::resize(size_t newSize) {
    std::lock_guard<std::mutex> lock(mutex_);
    
    // 如果新大小小于当前大小，移除多余资源
    while (availableResources_.size() > newSize) {
        availableResources_.pop();
    }
    
    // 如果新大小大于当前大小，添加新资源
    size_t currentSize = availableResources_.size() + inUseCount_;
    for (size_t i = currentSize; i < newSize; ++i) {
        auto resource = createResource();
        if (resource) {
            availableResources_.push({resource, std::chrono::steady_clock::now()});
        }
    }
    
    config_.maxSize = newSize;
}

template <typename T>
std::shared_ptr<T> ResourcePool<T>::createResource() {
    try {
        return createFunc_();
    } catch (...) {
        return nullptr;
    }
}

template <typename T>
void ResourcePool<T>::cleanupExpiredResources() {
    if (config_.maxIdleTime.count() <= 0) return;
    
    auto now = std::chrono::steady_clock::now();
    std::queue<PoolItem> validResources;
    
    while (!availableResources_.empty()) {
        auto& item = availableResources_.front();
        auto idleTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - item.lastUsed);
        
        if (idleTime < config_.maxIdleTime) {
            validResources.push(item);
        }
        
        availableResources_.pop();
    }
    
    availableResources_ = std::move(validResources);
}